#include <linux/spi/spi.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/random.h>
#include "ci522.h"

#define CI522_CNT	1
#define CI522_NAME	"ci522"
#define Debug_CI522  0/* 调试宏定义 */

struct ci522_dev {
	dev_t devid;				/* 设备号 	 */
	struct cdev cdev;			/* cdev 	*/
	struct class *class;		/* 类 		*/
	struct device *device;		/* 设备 	 */
	struct device_node	*nd; 	/* 设备节点 */
	int major;					/* 主设备号 */
    int reset_gpio; 			/* reset 所使用的 GPIO 编号 */
	void *private_data;			/* 私有数据 		*/

	uint8_t Ver_soin;
	unsigned char Send_Soc_Uid[4];
	// signed int gyro_x_adc;		/* 陀螺仪X轴原始值 	 */
	// signed int gyro_y_adc;		/* 陀螺仪Y轴原始值		*/
	// signed int gyro_z_adc;		/* 陀螺仪Z轴原始值 		*/
	// signed int accel_x_adc;		/* 加速度计X轴原始值 	*/
	// signed int accel_y_adc;		/* 加速度计Y轴原始值	*/
	// signed int accel_z_adc;		/* 加速度计Z轴原始值 	*/
	// signed int temp_adc;		/* 温度原始值 			*/
};

static struct ci522_dev ci522dev;



// static struct spi_driver ci522_spi_driver = {
// 	.driver = {
// 		.name =		"ci522",
// 		.of_match_table = of_match_ptr(spidev_dt_ids),
// 		.acpi_match_table = ACPI_PTR(spidev_acpi_ids),
// 	},
// 	.probe =	ci522_probe,
// 	.remove =	ci522_remove,
// };

// static int __init ci522_init(void)
// {
// 	int status;

// 	/* Claim our 256 reserved device numbers.  Then register a class
// 	 * that will key udev/mdev to add/remove /dev nodes.  Last, register
// 	 * the driver which manages those device numbers.
// 	 */
// 	BUILD_BUG_ON(N_SPI_MINORS > 256);
// 	status = register_chrdev(CI522_MAJOR, "spi", &ci522_fops);
// 	if (status < 0)
// 		return status;

// 	ci522_class = class_create(THIS_MODULE, "ci522");
// 	if (IS_ERR(ci522_class)) {
// 		unregister_chrdev(CI522_MAJOR, ci522_spi_driver.driver.name);
// 		return PTR_ERR(ci522_class);
// 	}

// 	status = spi_register_driver(&ci522_spi_driver);
// 	if (status < 0) {
// 		class_destroy(ci522_class);
// 		unregister_chrdev(CI522_MAJOR, ci522_spi_driver.driver.name);
// 	}
// 	return status;
// }
// module_init(ci522_init);

// static void __exit ci522_exit(void)
// {
// 	spi_unregister_driver(&ci522_spi_driver);
// 	class_destroy(ci522_class);
// 	unregister_chrdev(CI522_MAJOR, ci522_spi_driver.driver.name);
// }
// module_exit(ci522_exit);

/*-------------------------------------------------------------------------*/
/*
 * @description	: 从ci522读取多个寄存器数据
 * @param - dev:  ci522设备
 * @param - reg:  要读取的寄存器首地址
 * @param - val:  读取到的数据
 * @param - len:  要读取的数据长度
 * @return 		: 操作结果
 */
static int ci522_read_regs(struct ci522_dev *dev, u8 reg, void *buf, int len)
{

	int ret = -1;
	unsigned char txdata[1];
	unsigned char * rxdata;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
    
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	if(!t) {
		return -ENOMEM;
	}

	rxdata = kzalloc(sizeof(char) * len, GFP_KERNEL);	/* 申请内存 */
	if(!rxdata) {
		goto out1;
	}

	/* 一共发送len+1个字节的数据，第一个字节为
	寄存器首地址，一共要读取len个字节长度的数据，*/
	txdata[0] = reg | 0x80;		/* 写数据的时候首寄存器地址bit8要置1 */			
	t->tx_buf = txdata;			/* 要发送的数据 */
    t->rx_buf = rxdata;			/* 要读取的数据 */
	t->len = len+1;				/* t->len=发送的长度+读取的长度 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
	if(ret) {
		goto out2;
	}
	
    memcpy(buf , rxdata+1, len);  /* 只需要读取的数据 */

out2:
	kfree(rxdata);					/* 释放内存 */
out1:	
	kfree(t);						/* 释放内存 */
	
	return ret;
}

/*
 * @description	: 向ci522多个寄存器写入数据
 * @param - dev:  ci522设备
 * @param - reg:  要写入的寄存器首地址
 * @param - val:  要写入的数据缓冲区
 * @param - len:  要写入的数据长度
 * @return 	  :   操作结果
 */
static s32 ci522_write_regs(struct ci522_dev *dev, u8 reg, u8 *buf, u8 len)
{
	int ret = -1;
	unsigned char *txdata;
	struct spi_message m;
	struct spi_transfer *t;
	struct spi_device *spi = (struct spi_device *)dev->private_data;
	
	t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);	/* 申请内存 */
	if(!t) {
		return -ENOMEM;
	}
	
	txdata = kzalloc(sizeof(char)+len, GFP_KERNEL);
	if(!txdata) {
		goto out1;
	}
	
	/* 一共发送len+1个字节的数据，第一个字节为
	寄存器首地址，len为要写入的寄存器的集合，*/
	*txdata = reg & ~0x80;	/* 写数据的时候首寄存器地址bit8要清零 */
    memcpy(txdata+1, buf, len);	/* 把len个寄存器拷贝到txdata里，等待发送 */
	t->tx_buf = txdata;			/* 要发送的数据 */
	t->len = len+1;				/* t->len=发送的长度+读取的长度 */
	spi_message_init(&m);		/* 初始化spi_message */
	spi_message_add_tail(t, &m);/* 将spi_transfer添加到spi_message队列 */
	ret = spi_sync(spi, &m);	/* 同步发送 */
    if(ret) {
        goto out2;
    }
	
out2:
	kfree(txdata);				/* 释放内存 */
out1:
	kfree(t);					/* 释放内存 */
	return ret;
}

/*
 * @description	: 读取ci522指定寄存器值，读取一个寄存器
 * @param - dev:  ci522设备
 * @param - reg:  要读取的寄存器
 * @return 	  :   读取到的寄存器值
 */
static unsigned char ci522_read_onereg(struct ci522_dev *dev, u8 reg)
{
	u8 data = 0;
    reg = (reg & 0x3f) << 1 ;   //code the first byte	
	ci522_read_regs(dev, reg, &data, 1);
	return data;
}

/*
 * @description	: 向ci522指定寄存器写入指定的值，写一个寄存器
 * @param - dev:  ci522设备
 * @param - reg:  要写的寄存器
 * @param - data: 要写入的值
 * @return   :    无
 */	
static void ci522_write_onereg(struct ci522_dev *dev, u8 reg, u8 value)
{
	u8 buf = value;
    reg = (reg & 0x3f) << 1; 
	ci522_write_regs(dev, reg, &buf, 1);
}
/*ci522写函数*/
void I_CI522_IO_Write(unsigned char RegAddr, unsigned char value)
{
    ci522_write_onereg(&ci522dev, (u8)RegAddr, (u8)value);
}
/*ci522读函数*/
unsigned char I_CI522_IO_Read(unsigned char RegAddr)
{
    return ci522_read_onereg(&ci522dev, (u8)RegAddr);
}

//ci522_interfaces
void I_CI522_ClearBitMask(unsigned char reg,unsigned char mask)  
{
	char tmp = 0x00;
	tmp = I_CI522_IO_Read(reg);
	I_CI522_IO_Write(reg, tmp & ~mask);  // clear bit mask
} 

void I_CI522_SetBitMask(unsigned char reg,unsigned char mask)  
{
	char tmp = 0x00;
	tmp = I_CI522_IO_Read(reg);
	I_CI522_IO_Write(reg,tmp | mask);  // set bit mask
}

void I_CI522_SiModifyReg(unsigned char RegAddr, unsigned char ModifyVal, unsigned char MaskByte)
{
	unsigned char RegVal;
	RegVal = I_CI522_IO_Read(RegAddr);
	if(ModifyVal)
	{
			RegVal |= MaskByte;
	}
	else
	{
			RegVal &= (~MaskByte);
	}
	I_CI522_IO_Write(RegAddr, RegVal);
}


/*
 * @description	: 读取ci522的数据，读取原始数据，包括三轴陀螺仪、
 * 				: 三轴加速度计和内部温度。
 * @param - dev	: ci522设备
 * @return 		: 无。
 */
void ci522_readdata(struct ci522_dev *dev)
{
	// unsigned char data[14] = { 0 };
	// ci522_read_regs(dev, ICM20_ACCEL_XOUT_H, data, 14);

	// dev->accel_x_adc = (signed short)((data[0] << 8) | data[1]); 
	// dev->accel_y_adc = (signed short)((data[2] << 8) | data[3]); 
	// dev->accel_z_adc = (signed short)((data[4] << 8) | data[5]); 
	// dev->temp_adc    = (signed short)((data[6] << 8) | data[7]); 
	// dev->gyro_x_adc  = (signed short)((data[8] << 8) | data[9]); 
	// dev->gyro_y_adc  = (signed short)((data[10] << 8) | data[11]);
	// dev->gyro_z_adc  = (signed short)((data[12] << 8) | data[13]);
}

/*
 * @description		: 打开设备
 * @param - inode 	: 传递给驱动的inode
 * @param - filp 	: 设备文件，file结构体有个叫做pr似有ate_data的成员变量
 * 					  一般在open的时候将private_data似有向设备结构体。
 * @return 			: 0 成功;其他 失败
 */
static int ci522_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &ci522dev; /* 设置私有数据 */
	return 0;
}

/*
 * @description		: 从设备读取数据 
 * @param - filp 	: 要打开的设备文件(文件描述符)
 * @param - buf 	: 返回给用户空间的数据缓冲区
 * @param - cnt 	: 要读取的数据长度
 * @param - offt 	: 相对于文件首地址的偏移
 * @return 			: 读取的字节数，如果为负值，表示读取失败
 */
static ssize_t ci522_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{
	unsigned char data[5];
	long err = 0;
	struct ci522_dev *dev = (struct ci522_dev *)filp->private_data;
	unsigned char Found_Car_state = 0;
	// printk("\r\n read uid buf size: %d \r\n",cnt); // 暂时无用
	Found_Car_state = PCD_Ci522_TypeA_GetUID(); // 读A卡50ms
	// printk("Found_Car_state = %d\n", Found_Car_state);
	if (Found_Car_state != 0) {
		return -EFAULT; // 读取失败
	}
	// printk("dev->Send_Soc_Uid = %02x %02x %02x %02x\n", 
	// 			dev->Send_Soc_Uid[0], dev->Send_Soc_Uid[1], dev->Send_Soc_Uid[2], dev->Send_Soc_Uid[3]);
	data[0] = dev->Send_Soc_Uid[0];
	data[1] = dev->Send_Soc_Uid[1];
	data[2] = dev->Send_Soc_Uid[2];
	data[3] = dev->Send_Soc_Uid[3];
	data[4] = Found_Car_state; // 读取状态
	PcdAntennaOff();
	err = copy_to_user(buf, data, sizeof(data));
	if(err < 0){
		return 1;
	}
	return 0;
}

/*
* @description : 向设备写数据
* @param - filp : 设备文件，表示打开的文件描述符
* @param - buf : 要写给设备写入的数据
* @param - cnt : 要写入的数据长度
* @param - offt : 相对于文件首地址的偏移
* @return : 写入的字节数，如果为负值，表示写入失败
*/
static ssize_t ci522_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *off)
{
    char *str, *cmd, *value;
    unsigned char tmpbuf[128];
	struct ci522_dev *dev = (struct ci522_dev *)filp->private_data;
	unsigned char *Get_Uid = dev->Send_Soc_Uid;
	unsigned char Found_Car_state = 0;

	if (cnt >= sizeof(tmpbuf))
        goto error;

    if (!buf || copy_from_user(tmpbuf, buf, cnt) != 0)
        return 0;

	if (cnt > 0)
    {
        str = tmpbuf;
		printk("tmpbuf: %s\r\n", tmpbuf);
        cmd = strsep(&str, "\t \n");
        if (!cmd)
        {
            goto error;
        }
		if (strcmp(cmd, "getuid") == 0){
			// PcdAntennaOn();
			Found_Car_state = PCD_Ci522_TypeA_GetUID(); // 读A卡50ms
			printk("Found_Car_state = %d\n", Found_Car_state);
			if (Found_Car_state != 0) {
				// PcdAntennaOff();
				return -EFAULT; // 读取失败
			}
			printk("dev->Send_Soc_Uid = %02x %02x %02x %02x\n", 
				dev->Send_Soc_Uid[0], dev->Send_Soc_Uid[1], dev->Send_Soc_Uid[2], dev->Send_Soc_Uid[3]);
			// printk("ci522dev.Send_Soc_Uid = %02x %02x %02x %02x\n", 
			// 	ci522dev.Send_Soc_Uid[0], ci522dev.Send_Soc_Uid[1], ci522dev.Send_Soc_Uid[2], ci522dev.Send_Soc_Uid[3]);
			// printk("get uid = %02x %02x %02x %02x\n", 
			// 	*Get_Uid, *(Get_Uid+1), *(Get_Uid+2), *(Get_Uid+3));
			// printk("get uid = %02x %02x %02x %02x\n", 
			// 	Get_Uid[0], Get_Uid[1], Get_Uid[2], Get_Uid[3]);
		}else if(strcmp(cmd, "PcdAntennaOn") == 0){
			PcdAntennaOn();
		}else if(strcmp(cmd, "PcdAntennaOff") == 0){
			PcdAntennaOff();
		}else{
            goto error;
        }
    }
    return cnt;
error:
    printk("usage: \n");
    printk(" Get IDCard UID: for example; echo getuid > /dev/ci522\n");
    return -EFAULT;
	

	
	return 0;
}
/*
 * @description		: 关闭/释放设备
 * @param - filp 	: 要关闭的设备文件(文件描述符)
 * @return 			: 0 成功;其他 失败
 */
static int ci522_release(struct inode *inode, struct file *filp)
{
	return 0;
}

/* ci522操作函数 */
static const struct file_operations ci522_ops = {
	.owner = THIS_MODULE,
	.open = ci522_open,
	.read = ci522_read,
	.write = ci522_write,
	.release = ci522_release,
};

/***********************************************
 * 函数名：PcdAntennaOn
 * 描述  ：开启天线  每次启动或关闭天险发射之间应至少有1ms的间隔
 * 输入  ：无
 * 返回  : 无
 * 调用  ：外部调用
 **********************************************/

void PcdAntennaOn(void)
{
    unsigned char i;
    i = I_CI522_IO_Read(TxControlReg);
    if (!(i & 0x03))
    {
        I_CI522_SetBitMask(TxControlReg, 0x03); // bit1 bit0 置1
    }
}

/***********************************************
 * 函数名：PcdAntennaOff
 * 描述  ：关闭天线
 * 输入  ：无
 * 返回  : 无
 * 调用  ：外部调用
 **********************************************/
void PcdAntennaOff(void)
{
	I_CI522_ClearBitMask(TxControlReg, 0x03);  // bit1 bit0 清0
}

/////////////////////////////////////////////////////////////////////
//用MF522计算CRC16函数
/////////////////////////////////////////////////////////////////////

/***********************************************
 * 函数名：CalulateCRC
 * 描述  ：用MF522计算CRC16函数
 * 输入  ：
 * 返回  : 无
 * 调用  ：外部调用
 **********************************************/
void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData)
{
    unsigned char i,n;
    I_CI522_ClearBitMask(DivIrqReg,0x04);
    I_CI522_IO_Write(CommandReg,PCD_IDLE);
    I_CI522_SetBitMask(FIFOLevelReg,0x80);
    for (i=0; i<len; i++)
    {   
			I_CI522_IO_Write(FIFODataReg, *(pIndata+i));   
		}
    I_CI522_IO_Write(CommandReg, PCD_CALCCRC);
    i = 0xFF;
    do 
    {
        n = I_CI522_IO_Read(DivIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x04));
    pOutData[0] = I_CI522_IO_Read(CRCResultRegL);
    pOutData[1] = I_CI522_IO_Read(CRCResultRegH);
}


unsigned char aaa = 0;
/**************************************************************************************************
 * 函数名：PcdComMF522
 * 描述  ：通过RC522和ISO14443卡通讯
 * 输入  ：Command[IN]:RC522命令字              pInData[IN]:通过RC522发送到卡片的数据    InLenByte[IN]:发送数据的字节长度
 *       ：pOutData[OUT]:接收到的卡片返回数据   pOutLenBit[OUT]:返回数据的位长度
 * 返回  : 无 
 * 调用  ：外部调用
 *************************************************************************************************/
char PcdComMF522(unsigned char Command, 
                 unsigned char *pInData, 
                 unsigned char InLenByte,
                 unsigned char *pOutData, 
                 unsigned int *pOutLenBit)
{
    char status = MI_ERR;
    unsigned char irqEn   = 0x00;
    unsigned char waitFor = 0x00;
    unsigned char lastBits;
    unsigned char n;
    unsigned int i;
    switch (Command)
    {
        case PCD_AUTHENT:
			irqEn   = 0x12;
			waitFor = 0x10;
			break;
		case PCD_TRANSCEIVE:
			irqEn   = 0x77;
			waitFor = 0x30;
			break;
		default:
			break;
    }
   
    //I_CI522_IO_Write(ComIEnReg,irqEn|0x80);
    I_CI522_ClearBitMask(ComIrqReg,0x80);
    I_CI522_IO_Write(CommandReg,PCD_IDLE);
    I_CI522_SetBitMask(FIFOLevelReg,0x80);
    
    for (i=0; i<InLenByte; i++)
    {   
		I_CI522_IO_Write(FIFODataReg, pInData[i]);    
	}
    I_CI522_IO_Write(CommandReg, Command);
   
    if (Command == PCD_TRANSCEIVE)
    {    
		I_CI522_SetBitMask(BitFramingReg,0x80);  
	}
    
    //i = 600;//根据时钟频率调整，操作M1卡最大等待时间25ms
	i = 600;
    do 
    {
        n = I_CI522_IO_Read(ComIrqReg);
        i--;
    }
    while ((i!=0) && !(n&0x01) && !(n&waitFor));
    I_CI522_ClearBitMask(BitFramingReg,0x80);

    if (i!=0)
    {   
		aaa = I_CI522_IO_Read(ErrorReg);
		
        if(!(I_CI522_IO_Read(ErrorReg)&0x1B))
        {
            status = MI_OK;
            if (n & irqEn & 0x01)
            {   status = MI_NOTAGERR;   }
            if (Command == PCD_TRANSCEIVE)
            {
               	n = I_CI522_IO_Read(FIFOLevelReg);
              	lastBits = I_CI522_IO_Read(ControlReg) & 0x07;
                if (lastBits)
                {   
					*pOutLenBit = (n-1)*8 + lastBits;   
				}
                else
                {   
					*pOutLenBit = n*8;   
				}
                if (n == 0)
                {   
					n = 1;    
				}
                if (n > MAXRLEN)
                {   
					n = MAXRLEN;   
				}
                for (i=0; i<n; i++)
                {   
					pOutData[i] = I_CI522_IO_Read(FIFODataReg);    
				}
            }
        }
        else
        {   
			status = MI_ERR;   
		}
        
    }
   
    I_CI522_SetBitMask(ControlReg,0x80);           // stop timer now
    I_CI522_IO_Write(CommandReg,PCD_IDLE); 
    return status;
}

/********************************************************************
 * 函数功能：寻卡
 * 参数说明: req_code[IN]:寻卡方式
 *                0x52 = 寻感应区内所有符合14443A标准的卡
 *                0x26 = 寻未进入休眠状态的卡
 *          pTagType[OUT]：卡片类型代码
 *                0x4400 = Mifare_UltraLight
 *                0x0400 = Mifare_One(S50)
 *                0x0200 = Mifare_One(S70)
 *                0x0800 = Mifare_Pro(X)
 *                0x4403 = Mifare_DESFire
 * 返回值 : 成功返回MI_OK
 ********************************************************************/
char PcdRequest(unsigned char req_code,unsigned char *pTagType)
{
	char status;  
	unsigned int unLen;
	unsigned char ucComMF522Buf[MAXRLEN]; 

	I_CI522_ClearBitMask(Status2Reg,0x08);
	I_CI522_IO_Write(BitFramingReg,0x07);
	I_CI522_SetBitMask(TxControlReg,0x03);
 
	ucComMF522Buf[0] = req_code;

	status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);
	if ((status == MI_OK) && (unLen == 0x10))
	{    
		*pTagType     = ucComMF522Buf[0];
		*(pTagType+1) = ucComMF522Buf[1];
	}
	else
	{   
		status = MI_ERR;   
	}
   
	return status;
}


/////////////////////////////////////////////////////////////////////
//功    能：防冲撞
//参数说明: pSnr[OUT]:卡片序列号，4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////  
char PcdAnticoll(unsigned char *pSnr, unsigned char anticollision_level)
{
    char status;
    unsigned char i,snr_check=0;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    

    I_CI522_ClearBitMask(Status2Reg,0x08);
    I_CI522_IO_Write(BitFramingReg,0x00);
    I_CI522_ClearBitMask(CollReg,0x80);
 
    ucComMF522Buf[0] = anticollision_level;
    ucComMF522Buf[1] = 0x20;

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);

    if (status == MI_OK)
	{
		for (i=0; i<4; i++)
		{   
			*(pSnr+i)  = ucComMF522Buf[i];
			snr_check ^= ucComMF522Buf[i];
		}
		if (snr_check != ucComMF522Buf[i])
   		{   
			status = MI_ERR;    
		}
    }
    
    I_CI522_SetBitMask(CollReg,0x80);
    return status;
}


/////////////////////////////////////////////////////////////////////
//功    能：选定卡片
//参数说明: pSnr[IN]:卡片序列号，4字节
//返    回: 成功返回MI_OK
////////////////////////////////////////////////////////////////////
char PcdSelect (unsigned char * pSnr, unsigned char *sak)
{
    char status;
    unsigned char i;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
    	ucComMF522Buf[i+2] = *(pSnr+i);
    	ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);                                                                      
  
    I_CI522_ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   
		*sak = ucComMF522Buf[0];
		status = MI_OK;  
	}
    else
    {   
		status = MI_ERR;    
	}

    return status;
}

char PcdSelect1 (unsigned char * pSnr, unsigned char *sak)
{
    char status;
    unsigned char i;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL1;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
    	ucComMF522Buf[i+2] = *(pSnr+i);
    	ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    I_CI522_ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   
		*sak = ucComMF522Buf[0];
		status = MI_OK;  
	}
    else
    {   
		status = MI_ERR;    
	}

    return status;
}

char PcdSelect2 (unsigned char * pSnr, unsigned char *sak)
{
    char status;
    unsigned char i;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL2;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
    	ucComMF522Buf[i+2] = *(pSnr+i);
    	ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    I_CI522_ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   
		*sak = ucComMF522Buf[0];
		status = MI_OK;  
	}
    else
    {   
		status = MI_ERR;    
	}

    return status;
}

char PcdSelect3 (unsigned char * pSnr, unsigned char *sak)
{
    char status;
    unsigned char i;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_ANTICOLL2;
    ucComMF522Buf[1] = 0x70;
    ucComMF522Buf[6] = 0;
    for (i=0; i<4; i++)
    {
    	ucComMF522Buf[i+2] = *(pSnr+i);
    	ucComMF522Buf[6]  ^= *(pSnr+i);
    }
    CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);
  
    I_CI522_ClearBitMask(Status2Reg,0x08);

    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);
    
    if ((status == MI_OK) && (unLen == 0x18))
    {   
		*sak = ucComMF522Buf[0];
		status = MI_OK;  
	}
    else
    {   
		status = MI_ERR;    
	}

    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：命令卡片进入休眠状态
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////
char PcdHalt(void)
{
    char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_HALT;
    ucComMF522Buf[1] = 0;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：验证卡片密码
//参数说明: auth_mode[IN]: 密码验证模式
//                 0x60 = 验证A密钥
//                 0x61 = 验证B密钥 
//          addr[IN]：块地址
//          pKey[IN]：密码
//          pSnr[IN]：卡片序列号，4字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////               
char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr)
{
    char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = auth_mode;
    ucComMF522Buf[1] = addr;
	memcpy(&ucComMF522Buf[2], pKey, 6); 
	memcpy(&ucComMF522Buf[8], pSnr, 6); 
    
    status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);
    if ((status != MI_OK) || (!(I_CI522_IO_Read(Status2Reg) & 0x08)))
    {
		status = MI_ERR;   
	}
    
    return status;
}



/////////////////////////////////////////////////////////////////////
//功    能：读取M1卡一块数据
//参数说明: addr[IN]：块地址
//          pData[OUT]：读出的数据，16字节
//返    回: 成功返回MI_OK
///////////////////////////////////////////////////////////////////// 
char PcdRead(unsigned char addr,unsigned char *pData)
{
    char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 

    ucComMF522Buf[0] = PICC_READ;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
   
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);
    if ((status == MI_OK) && (unLen == 0x90))
   	{   
		memcpy(pData, ucComMF522Buf, 16);   
	}
    else
    {   
		status = MI_ERR;   
	}
    
    return status;
}

/////////////////////////////////////////////////////////////////////
//功    能：写数据到M1卡一块
//参数说明: addr[IN]：块地址
//          pData[IN]：写入的数据，16字节
//返    回: 成功返回MI_OK
/////////////////////////////////////////////////////////////////////                  
char PcdWrite(unsigned char addr,unsigned char *pData)
{
    char status;
    unsigned int unLen;
    unsigned char ucComMF522Buf[MAXRLEN]; 
    
    ucComMF522Buf[0] = PICC_WRITE;
    ucComMF522Buf[1] = addr;
    CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);
 
    status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
    {   
		status = MI_ERR;   
	}
        
    if (status == MI_OK)
    {
        memcpy(ucComMF522Buf, pData, 16);
        CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);

        status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A))
        {   
			status = MI_ERR;   
		}
    }
    
    return status;
}

/*=================================
 函数功能：循环读取A卡UID

=================================*/
void PCD_CI522_TypeA(void) // 不使用
{
//	LED_OperaSuccess();	// LED indicator
	
	while(1)
	{
		PCD_Ci522_TypeA_GetUID();		//读A卡
        

        ci522dev.Ver_soin=I_CI522_IO_Read(VersionReg);
        
        #if Debug_CI522
          printk("\r\nVer_soin=%d\r\n",ci522dev.Ver_soin);
        #endif
		
		//PCD_Ci522_TypeA_rw_block();		//读A卡扇区

		mdelay(500);
	}
}

/*===============================
 函数功能：读A卡初始化配置

 ================================*/
void PCD_Ci522_TypeA_Init(void)
{
	I_CI522_ClearBitMask(Status2Reg, 0x08);  
	// Reset baud rates
	I_CI522_IO_Write(TxModeReg, 0x00);
	I_CI522_IO_Write(RxModeReg, 0x00);
	// Reset ModWidthReg
	I_CI522_IO_Write(ModWidthReg, 0x26);
	// RxGain:110,43dB by default;
	I_CI522_IO_Write(RFCfgReg, RFCfgReg_Val);
	// When communicating with a PICC we need a timeout if something goes wrong.
	// f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo].
	// TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg.
	I_CI522_IO_Write(TModeReg, 0x80);// TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds
	I_CI522_IO_Write(TPrescalerReg, 0xa9);// TPreScaler = TModeReg[3..0]:TPrescalerReg
	I_CI522_IO_Write(TReloadRegH, 0x03); // Reload timer 
	I_CI522_IO_Write(TReloadRegL, 0xe8); // Reload timer 
	I_CI522_IO_Write(TxASKReg, 0x40);	// Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting
	I_CI522_IO_Write(ModeReg, 0x3D);	// Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4)
	I_CI522_IO_Write(CommandReg, 0x00);  // Turn on the analog part of receiver   

	PcdAntennaOn();
    
	ci522dev.Ver_soin=I_CI522_IO_Read(VersionReg);
	printk("\r\nVer_soin=%d\r\n",ci522dev.Ver_soin);
}

char PCD_Ci522_TypeA_GetUID(void)
{
	unsigned char ATQA[2];
	unsigned char UID[12];
	unsigned char SAK = 0;
	unsigned char UID_complate1 = 0;
	unsigned char UID_complate2 = 0;
    
    // memset(Send_Soc_Uid,0,4);
	memset(ci522dev.Send_Soc_Uid,0,4);

    #if Debug_CI522
	printk("\r\nTest_Si522_GetUID");
    #endif
    
	I_CI522_IO_Write(RFCfgReg, RFCfgReg_Val); //复位接收增益
	
	//寻卡
	if( PcdRequest( PICC_REQIDL, ATQA) != MI_OK )  //寻天线区内未进入休眠状态的卡，返回卡片类型 2字节	
	{
		I_CI522_IO_Write(RFCfgReg, 0x48);
		if(PcdRequest( PICC_REQIDL, ATQA) != MI_OK)
		{
			I_CI522_IO_Write(RFCfgReg, 0x58);
			if(PcdRequest( PICC_REQIDL, ATQA) != MI_OK)
			{	
                #if Debug_CI522
				printk("\r\nRequest:fail");
                #endif
				return 1;
			}
			else
			{
                #if Debug_CI522
				printk("\r\nRequest1:ok  ATQA:%02x %02x",ATQA[0],ATQA[1]);
                #endif
			}	
		}
		else
		{
            #if Debug_CI522
			printk("\r\nRequest2:ok  ATQA:%02x %02x",ATQA[0],ATQA[1]);
            #endif
		}		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nRequest3:ok  ATQA:%02x %02x",ATQA[0],ATQA[1]);
        #endif
	}
	
	
//UID长度=4
	//Anticoll 冲突检测 level1
	if(PcdAnticoll(UID, PICC_ANTICOLL1)!= MI_OK) 
	{
        #if Debug_CI522
		printk("\r\nAnticoll1:fail");
        #endif
		return 2;		
	}
	else
	{
		if(PcdSelect1(UID,&SAK)!= MI_OK)
		{
            #if Debug_CI522
			printk("\r\nSelect1:fail");
            #endif
			return 1;		
		}
		else
		{
            #if Debug_CI522
			printk("\r\nSelect1:ok  SAK1:%02x",SAK);
            #endif
			if(SAK&0x04)                         
			{
				UID_complate1 = 0;
				
				//UID长度=7
				if(UID_complate1 == 0)    
				{
					//Anticoll 冲突检测 level2
					if(PcdAnticoll(UID+4, PICC_ANTICOLL2)!= MI_OK) 
					{
                        #if Debug_CI522
						printk("\r\nAnticoll2:fail");
                        #endif
						return 1;		
					}
					else
					{
						if(PcdSelect2(UID+4,&SAK)!= MI_OK)  
						{
                            #if Debug_CI522
							printk("\r\nSelect2:fail");
                            #endif
							return 1;		
						}
						else
						{
                            #if Debug_CI522
							printk("\r\nSelect2:ok  SAK2:%02x",SAK);
                            #endif
							if(SAK&0x04)                         
							{
								UID_complate2 = 0;
								
								//UID长度=10
								if(UID_complate2 == 0)     
								{
									//Anticoll 冲突检测 level3
									if(PcdAnticoll(UID+8, PICC_ANTICOLL3)!= MI_OK) 
									{
                                        #if Debug_CI522
										printk("\r\nAnticoll3:fail");
                                        #endif
										return 1;		
									}
									else
									{
										if(PcdSelect3(UID+8,&SAK)!= MI_OK)  
										{
                                            #if Debug_CI522
											printk("\r\nSelect3:fail");
                                            #endif
											return 1;		
										}
										else
										{
                                            #if Debug_CI522
											printk("\r\nSelect3:ok  SAK3:%02x",SAK);
                                            #endif
											if(SAK&0x04)                          
											{
//												UID_complate3 = 0;
											}
											else 
											{
	//											UID_complate3 = 1;     
                                                #if Debug_CI522                                                
												printk("\r\nAnticoll3:ok  UID:%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
												UID[1],UID[2],UID[3],UID[5],UID[6],UID[7],UID[8],UID[9],UID[10],UID[11]);		
                                                #endif                                                
											}					
										}							
									}
								}
							}
							else 
							{
								UID_complate2 = 1;    
                                #if Debug_CI522                                
								printk("\r\nAnticoll2:ok  UID:%02x %02x %02x %02x %02x %02x %02x",
								UID[1],UID[2],UID[3],UID[4],UID[5],UID[6],UID[7]);
                                #endif
							}	
						}			
					}
				}
			}
			else 
			{
				UID_complate1 = 1;      
                #if Debug_CI522                
				printk("\r\nAnticoll1:ok  UID:%02x %02x %02x %02x",UID[0],UID[1],UID[2],UID[3]);
                #endif
                // memcpy(Send_Soc_Uid,UID,4);
				memcpy(ci522dev.Send_Soc_Uid,UID,4);
			}
		}		
	}
	//Halt
//	if(PcdHalt() != MI_OK)
//	{
//		printk("\r\nHalt:fail");
//		return 1;		
//	}
//	else
//	{
//		printk("\r\nHalt:ok");
//	}	
	
	udelay(100);
	return 0;
}

char PCD_Ci522_TypeA_rw_block(void)
{
	unsigned char ATQA[2];
	unsigned char UID[12];
	unsigned char SAK = 0;
	unsigned char CardReadBuf[16] = {0};
	unsigned char CardWriteBuf[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
	unsigned char DefaultKeyABuf[10] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
    unsigned char i;

    #if Debug_CI522
	printk("\r\n\r\nTest_Si522_GetCard");
    #endif
	
	//request 寻卡
	if( PcdRequest( PICC_REQIDL, ATQA) != MI_OK )  //寻天线区内未进入休眠状态的卡，返回卡片类型 2字节	
	{
        #if Debug_CI522
		printk("\r\nRequest:fail");
        #endif
		return 1;		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nRequest:ok  ATQA:%02x %02x",ATQA[0],ATQA[1]);
        #endif
	}
	

	//Anticoll 冲突检测
	if(PcdAnticoll(UID, PICC_ANTICOLL1)!= MI_OK)
	{	
        #if Debug_CI522        
		printk("\r\nAnticoll:fail");
        #endif
		return 1;		
	}
	else
	{	
        #if Debug_CI522
		printk("\r\nAnticoll:ok  UID:%02x %02x %02x %02x",UID[0],UID[1],UID[2],UID[3]);
        #endif
	}
	
	//Select 选卡
	if(PcdSelect1(UID,&SAK)!= MI_OK)
	{
        #if Debug_CI522
		printk("\r\nSelect:fail");
        #endif
		return 1;		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nSelect:ok  SAK:%02x",SAK);
        #endif
	}

	//Authenticate 验证密码
	if(PcdAuthState( PICC_AUTHENT1A, 4, DefaultKeyABuf, UID ) != MI_OK )
	{
        #if Debug_CI522
		printk("\r\nAuthenticate:fail");
        #endif
		return 1;		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nAuthenticate:ok");
        #endif
	}

	//读BLOCK原始数据
	if( PcdRead( 4, CardReadBuf ) != MI_OK )
	{
        #if Debug_CI522
		printk("\r\nPcdRead:fail");
        #endif
		return 1;		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nPcdRead:ok  ");
        #endif
		for(i=0;i<16;i++)
		{
            #if Debug_CI522
			printk(" %02x",CardReadBuf[i]);
            #endif
		}
	}

	//产生随机数
	for(i=0;i<16;i++)
		CardWriteBuf[i] = prandom_u32() & 0xFF; //随机数

	//写BLOCK 写入新的数据
	if( PcdWrite( 4, CardWriteBuf ) != MI_OK )
	{
        #if Debug_CI522
		printk("\r\nPcdWrite:fail");
        #endif
		return 1;	
	}
	else
	{
        #if Debug_CI522
		printk("\r\nPcdWrite:ok  ");
        #endif
		for(i=0;i<16;i++)
		{
            #if Debug_CI522
			printk(" %02x",CardWriteBuf[i]);
            #endif
		}
	}
		
	//读BLOCK 读出新写入的数据
	if( PcdRead( 4, CardReadBuf ) != MI_OK )
	{
        #if Debug_CI522
		printk("\r\nPcdRead:fail");
        #endif
		return 1;		
	}
	else
	{
        #if Debug_CI522
		printk("\r\nPcdRead:ok  ");
        #endif
		for(i=0;i<16;i++)
		{
            #if Debug_CI522
			printk(" %02x",CardReadBuf[i]);
            #endif
		}
	}
		
//	//Halt
//	if(PcdHalt() != MI_OK)
//	{
//		printk("\r\nHalt:fail");
//		return 1;		
//	}
//	else
//	{
//		printk("\r\nHalt:ok");
//	}	
	
	return 0;
}

//***********************************//修改新增内容

/***********************************************
 * 函数名：PcdReset
 * 描述  ：复位RC522 
 * 输入  ：无
 * 返回  : 无
 * 调用  ：外部调用
 **********************************************/
void PcdReset ( void )
{
	//hard reset
//	HAL_GPIO_WritePin(S52_NRSTPD_GPIO_Port,S52_NRSTPD_Pin,GPIO_PIN_RESET);
//	delay_us(100);
//	HAL_GPIO_WritePin(S52_NRSTPD_GPIO_Port,S52_NRSTPD_Pin,GPIO_PIN_SET);
//	delay_us(100);
	
	I_CI522_IO_Write(CommandReg, 0x0f);			      //向CommandReg 写入 0x0f	作用是使RC522复位
	while(I_CI522_IO_Read(CommandReg) & 0x10 );	  //Powerdown位为0时，表示RC522已准备好
	udelay(100);
}

void PcdPowerdown (void) //硬复位
{
	//hard reset
	gpio_set_value(ci522dev.reset_gpio, 0); /* set STB HIGH */
	mdelay(5);
	gpio_set_value(ci522dev.reset_gpio, 1); /* set STB HIGH */
	mdelay(5);
}

 /*
  * @description     : spi驱动的probe函数，当驱动与
  *                    设备匹配以后此函数就会执行
  * @param - client  : spi设备
  * @param - id      : spi设备ID
  * 
  */	
static int ci522_probe(struct spi_device *spi)
{
	int ret = 0;
    const char *str;
	/* 1、获取设备节点：stb-set */
    ci522dev.nd = of_find_node_by_name(NULL,"spi-ci522");
    if(ci522dev.nd == NULL) {
        printk("ci522dev node not find!\r\n");
        return -EINVAL;
    }

    /* 2.读取 status 属性 */
    ret = of_property_read_string(ci522dev.nd, "status", &str);
    if(ret < 0)
        return -EINVAL;

    if (strcmp(str, "okay"))
        return -EINVAL;
	
	/* 3、 获取设备树中的 gpio 属性，得到 STB 所使用的 gpio 编号 */
    ci522dev.reset_gpio = of_get_named_gpio(ci522dev.nd, "reset-gpio", 0);
    if(ci522dev.reset_gpio < 0) {
        printk("can't get gpios");
        return -EINVAL;
    }
    printk("stb-gpio num = %d\r\n", ci522dev.reset_gpio);

    /* 4.向 gpio 子系统申请使用 GPIO */
    ret = gpio_request(ci522dev.reset_gpio, "RESET-GPIO");
    if (ret) {
        printk(KERN_ERR "ci522dev: Failed to request reset-gpio\n");
        return ret;
    }

    /* 5、设置 Pc6 为输出，并且输出高电平 */
    ret = gpio_direction_output(ci522dev.reset_gpio, 1);
    if(ret < 0) {
        printk("can't set gpio!\r\n");
    }

	/* 1、构建设备号 */
	if (ci522dev.major) {
		ci522dev.devid = MKDEV(ci522dev.major, 0);
		register_chrdev_region(ci522dev.devid, CI522_CNT, CI522_NAME);
		if(ret < 0) {
            pr_err("cannot register %s char driver [ret=%d]\n", CI522_NAME, CI522_CNT);
            goto free_gpio;
        }
	} else {
		alloc_chrdev_region(&ci522dev.devid, 0, CI522_CNT, CI522_NAME);
			if(ret < 0) {
            pr_err("%s Couldn't alloc_chrdev_region, ret=%d\r\n", CI522_NAME, ret);
            goto free_gpio;
        }
		ci522dev.major = MAJOR(ci522dev.devid);
	}

	/* 2、注册设备 */
	cdev_init(&ci522dev.cdev, &ci522_ops);
	cdev_add(&ci522dev.cdev, ci522dev.devid, CI522_CNT);

	/* 3、创建类 */
	ci522dev.class = class_create(THIS_MODULE, CI522_NAME);
	if (IS_ERR(ci522dev.class)) {
		return PTR_ERR(ci522dev.class);
	}

	/* 4、创建设备 */
	ci522dev.device = device_create(ci522dev.class, NULL, ci522dev.devid, NULL, CI522_NAME);
	if (IS_ERR(ci522dev.device)) {
		return PTR_ERR(ci522dev.device);
	}

	/*初始化spi_device */
	spi->mode = SPI_MODE_0;	/*MODE0，CPOL=0，CPHA=0*/
	spi_setup(spi);
	ci522dev.private_data = spi; /* 设置私有数据 */

	// /* 初始化ci522内部寄存器 */
	PCD_Ci522_TypeA_Init();	
	
	free_gpio:
    gpio_free(ci522dev.reset_gpio);
	return 0;
}

/*
 * @description     : spi驱动的remove函数，移除i2c驱动的时候此函数会执行
 * @param - client 	: spi设备
 * @return          : 0，成功;其他负值,失败
 */
static int ci522_remove(struct spi_device *spi)
{
	/* 删除设备 */
	cdev_del(&ci522dev.cdev);
	unregister_chrdev_region(ci522dev.devid, CI522_CNT);

	/* 注销掉类和设备 */
	device_destroy(ci522dev.class, ci522dev.devid);
	class_destroy(ci522dev.class);
	gpio_free(ci522dev.reset_gpio); /* 释放 GPIO */
	return 0;
}

/* 传统匹配方式ID列表 */
static const struct spi_device_id ci522_id[] = {
	{"artinchip,ci522", 0},  
	{}
};

/* 设备树匹配列表 */
static const struct of_device_id ci522_of_match[] = {
	{ .compatible = "artinchip,ci522" },
	{ /* Sentinel */ }
};

/* SPI驱动结构体 */	
static struct spi_driver ci522_driver = {
	.probe = ci522_probe,
	.remove = ci522_remove,
	.driver = {
			.owner = THIS_MODULE,
		   	.name = "ci522",
		   	.of_match_table = ci522_of_match, 
		   },
	.id_table = ci522_id,
};
		   
/*
 * @description	: 驱动入口函数
 * @param 		: 无
 * @return 		: 无
 */
static int __init ci522_init(void)
{
	return spi_register_driver(&ci522_driver);
}

/*
 * @description	: 驱动出口函数
 * @param 		: 无
 * @return 		: 无
 */
static void __exit ci522_exit(void)
{
	spi_unregister_driver(&ci522_driver);
}

module_init(ci522_init);
module_exit(ci522_exit);

MODULE_DESCRIPTION("User mode SPI device interface");
MODULE_LICENSE("GPL");
MODULE_ALIAS("spi:ci522");